import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

/**
 * Constructs a data structure assigning Territories to Continents from a file.
 * 
 * @author joncaddey
 * @version 1.0
 */
public class ContinentReader {


	private List<Continent> my_continents;
	private List<Territory> my_territories;

	// TODO should this only be allowed to read once?
	/**
	 * <p>
	 * the_scanner must be of input as follows: for each Continent, the name of
	 * the Continent appears alone on its own line. the next line contains the
	 * integer value of the Continent. Each line after that contains the name of
	 * a Territory in the Continent. A blank line indicates all Territories for
	 * that Continent have been named. Whitespace before and after names are
	 * ignored.
	 * </p>
	 * <p>
	 * Continent names cannot repeat. It is allowed for the same Territory to be
	 * in two different Continents.
	 * </p>
	 * 
	 * @requires
	 * @ensures
	 * @param the_scanner
	 * @return
	 */
	// TEST COMPLETE? TODO
	// DOC COMPLETE? TODO
	// O(n^2) because of check for duplicate Continents.  Don't care for small file sizes.
	protected void read(final Scanner the_scanner) {

		List<Continent> temp_continents = new ArrayList<Continent>();
		Map<String, Territory> temp_territories = new HashMap<String, Territory>();
		String line;

		// file must not be empty
		if (!the_scanner.hasNextLine()) {
			throw new IllegalArgumentException(
					"Continent input must not be empty");
		}

		// read information for every continent
		while (the_scanner.hasNextLine()) {
			line = the_scanner.nextLine().trim();
			final String continent_name = line;
			if (line.length() == 0) {
				throw new IllegalArgumentException(
						"Continent name must have a non-whitespace character");
			}

			// No duplicates allowed
			// NOTE: This makes the entire method O(n^2), but I don't think the file size
			// will _ever_ make that matter.
			for (Continent c : temp_continents) {
				if (c.getName().equals(continent_name)) {
					throw new IllegalArgumentException(continent_name
							+ " has already been encountered");
				}
			}

			// there must be a continent value
			if (!the_scanner.hasNextLine()) {
				throw new IllegalArgumentException(
						continent_name
								+ " must have a Continent value on the line below its name");
			}

			// the continent value must be parseable as an int
			line = the_scanner.nextLine();
			final int value;
			try {
				value = Integer.parseInt(line);
			} catch (final NumberFormatException the_e) {
				throw new IllegalArgumentException(line
						+ " is not a valid Continent value for "+ continent_name + "--must be an integer below the continent name");
			}

			final List<Territory> territories = new ArrayList<Territory>();
			while (the_scanner.hasNextLine()) {
				line = the_scanner.nextLine().trim();
				if (line.length() == 0) {
					break;
				} else {
					final Territory lookup = temp_territories.get(line);
					if (lookup == null) {
						final Territory territory = new State(line);
						temp_territories.put(line, territory);
						territories.add(territory);
					} else {
						territories.add(lookup);
					}
				}
			}

			if (territories.isEmpty()) {
				throw new IllegalArgumentException(continent_name
						+ " must have at least one Territory");
			}
			temp_continents.add(new Continent(continent_name, value, territories));
		}

		// finished reading all continents successfully
		my_continents = temp_continents;
		my_territories = new ArrayList<Territory>(temp_territories.values());
	}

	public static void main(String args[]) {
		ContinentReader reader = new ContinentReader();
		try {
		reader.read(new Scanner(new File("/home/joncaddey/Documents/Risk/workspace-su-11-risk/risk/src/continents.txt")));
		} catch (IOException e) {
			System.err.println(e);
		}
		List<Continent> continents = reader.getContinents();
		for (Continent c : continents) {
			System.out.println(c);
		}
	}

	/**
	 * Returns a list of all Continents read in.value
	 * 
	 * @requires read() has been invoked.
	 * @ensures
	 * @return List of all Continents read in.
	 */
	// TEST COMPLETE? TODO
	// DOC COMPLETE? TODO
	public List<Continent> getContinents() {
		return new ArrayList<Continent>(my_continents);
	}
	
	
	/**
	 * @requires read() has been invoked.
	 * @ensures
	 * @return a list of all Territories read in.
	 */
	public Collection<Territory> getTerritories() {
		return new ArrayList<Territory>(my_territories);
	}
	
	
}
